package com.quectel.core.module.resource.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.constants.RedisCacheConstants;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.entity.DeviceCategoryEntity;
import com.quectel.core.module.device.entity.DeviceTypeEntity;
import com.quectel.core.module.resource.dao.ResourceGroupDao;
import com.quectel.core.module.resource.dao.ResourceGroupRelationDao;
import com.quectel.core.module.resource.dto.ResourceGroupDto;
import com.quectel.core.module.resource.dto.ResourceGroupRelationDto;
import com.quectel.core.module.resource.entity.ResourceGroupEntity;
import com.quectel.core.module.resource.entity.ResourceGroupRelationEntity;
import com.quectel.core.module.resource.service.ResourceGroupService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mybatis.MyBatisPlusUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2021-12-08 16:11:40
 */
@DubboService
public class ResourceGroupServiceImpl extends ServiceImpl<ResourceGroupRelationDao, ResourceGroupRelationEntity> implements ResourceGroupService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceGroupServiceImpl.class);

    private static final String RESOURCE_GROUP_CACHE_BY_ID = RedisCacheConstants.PROJECT_NAME + "RESOURCE_GROUP_CACHE_BY_ID:";
    private static final String RESOURCE_GROUP_CACHE_BY_CODE = RedisCacheConstants.PROJECT_NAME + "RESOURCE_GROUP_CACHE_BY_CODE:";


    @Autowired
    private ResourceGroupDao resourceGroupDao;
    @Autowired
    private ResourceGroupRelationDao resourceGroupRelationDao;

    @Override
    public ResourceGroupDto selectByCacheCode(String code) {
        ResourceGroupDto dto = CacheKit.cacheToRedis(() -> {
            ResourceGroupEntity resourceGroupEntity = resourceGroupDao.selectOne(new LambdaQueryWrapper<ResourceGroupEntity>().eq(ResourceGroupEntity::getCode, code));
            return paddingField(CopyUtils.copyObj(resourceGroupEntity, ResourceGroupDto.class));
        }, RESOURCE_GROUP_CACHE_BY_CODE + code, 5 * 60);
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateResources(Long resourceGroupId, Long[] categoryIds, Long[] typeIds) {
        ResourceGroupDto resourceGroupDto = selectCacheById(resourceGroupId);
        if (resourceGroupDto == null) {
            return;
        }


        deleteByResourceGroupId(resourceGroupId);


        List<ResourceGroupRelationEntity> saveList = Arrays.stream(categoryIds).map(o -> {
            ResourceGroupRelationEntity resourceGroupRelationEntity = new ResourceGroupRelationEntity();
            resourceGroupRelationEntity.setId(Snowflake.nextId());
            resourceGroupRelationEntity.setResourceGroupId(resourceGroupDto.getId());
            resourceGroupRelationEntity.setResourceGroupCode(resourceGroupDto.getCode());
            resourceGroupRelationEntity.setType(ResourceGroupRelationDto.RelationTypeEnum.Category.getType());
            resourceGroupRelationEntity.setResourceId(o);
            return resourceGroupRelationEntity;
        }).collect(Collectors.toList());

        saveList.addAll(Arrays.stream(typeIds).map(o -> {
            ResourceGroupRelationEntity resourceGroupRelationEntity = new ResourceGroupRelationEntity();
            resourceGroupRelationEntity.setId(Snowflake.nextId());
            resourceGroupRelationEntity.setResourceGroupId(resourceGroupDto.getId());
            resourceGroupRelationEntity.setResourceGroupCode(resourceGroupDto.getCode());
            resourceGroupRelationEntity.setType(ResourceGroupRelationDto.RelationTypeEnum.Type.getType());
            resourceGroupRelationEntity.setResourceId(o);
            return resourceGroupRelationEntity;
        }).collect(Collectors.toList()));

        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_ID + resourceGroupDto.getId());
        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_CODE + resourceGroupDto.getCode());

        super.saveBatch(saveList);
    }

    private void deleteByResourceGroupId(Long resourceGroupId) {
        resourceGroupRelationDao
                .delete(new LambdaQueryWrapper<ResourceGroupRelationEntity>()
                        .eq(ResourceGroupRelationEntity::getResourceGroupId, resourceGroupId));
    }

    @Override
    public ResourceGroupDto selectCacheById(Long id) {
        return CacheKit.cacheToRedis(
                () -> selectById(id),
                RESOURCE_GROUP_CACHE_BY_ID + id,

                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS
        );
    }

    @Override
    public ResourceGroupDto selectById(Long id) {
        ResourceGroupEntity entity = resourceGroupDao.selectById(id);
        return paddingField(CopyUtils.copyObj(entity, ResourceGroupDto.class));
    }

    @Override
    public List<ResourceGroupDto> queryList(Map<String, Object> params) {
        List<ResourceGroupEntity> list = resourceGroupDao.queryList(params);
        List<ResourceGroupDto> result = CopyUtils.copyList(list, ResourceGroupDto.class);
        result.forEach(this::paddingField);
        return result;
    }

    private ResourceGroupDto paddingField(ResourceGroupDto dto) {
        if (dto != null) {
            List<DeviceCategoryEntity> deviceCategoryEntities = resourceGroupRelationDao.findCategoriesByGroupId(dto.getId());
            List<DeviceTypeEntity> deviceTypeEntities = resourceGroupRelationDao.findTypesByGroupId(dto.getId());
            dto.setDeviceCategorys(CopyUtils.copyList(deviceCategoryEntities, DeviceCategoryDto.class));
            dto.setDeviceTypes(CopyUtils.copyList(deviceTypeEntities, DeviceTypeDto.class));
        }
        return dto;
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return resourceGroupDao.queryTotal(params);
    }

    @Override
    public Long save(ResourceGroupDto dto) {
        ResourceGroupEntity entity = CopyUtils.copyObj(dto, ResourceGroupEntity.class);
        entity.setId(Snowflake.nextId());
        resourceGroupDao.insert(entity);
        return entity.getId();
    }

    @Override
    public void updateById(ResourceGroupDto dto) {
        ResourceGroupEntity entity = CopyUtils.copyObj(dto, ResourceGroupEntity.class);
        resourceGroupDao.updateById(entity);
        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_ID + dto.getId());
        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_CODE + dto.getCode());
    }

    @Override
    public void updateAllColumnById(ResourceGroupDto dto) {
        ResourceGroupEntity entity = CopyUtils.copyObj(dto, ResourceGroupEntity.class);


        MyBatisPlusUtils.updateAllColumnById(entity, resourceGroupDao);

        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_ID + dto.getId());
        CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_CODE + dto.getCode());
    }

    @Override
    public void deleteById(Long id) {
        ResourceGroupDto resourceGroupDto = selectById(id);
        if (resourceGroupDto != null) {
            resourceGroupDao.deleteById(id);
            CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_ID + id);
            CacheKit.invalidRedisCache(RESOURCE_GROUP_CACHE_BY_CODE + resourceGroupDto.getCode());

            deleteByResourceGroupId(id);
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            deleteById(id);
        }
    }
}
